﻿namespace Atomic.Extensions
{
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Reflection;

    /// <summary>
    /// 类型扩展。
    /// </summary>
    public static class TypeExtensions
    {
        /// <summary>
        /// 当前对象是否为 NULL。
        /// </summary>
        /// <typeparam name="T">对象类型。</typeparam>
        /// <param name="t">对象。</param>
        /// <returns>如果当前对象为 null，则为 true， 否则为 false。</returns>
        public static bool IsNull<T>(this T t)
        {
            return t == null;
        }

        /// <summary>
        /// 当前对象是否不为 NULL。
        /// </summary>
        /// <typeparam name="T">对象类型。</typeparam>
        /// <param name="t">对象。</param>
        /// <returns>如果当前对象不为 null，则为 true；否则为 false。</returns>
        public static bool IsNotNull<T>(this T t)
        {
            return t != null;
        }

        /// <summary>
        /// 类型转换。
        /// </summary>
        /// <typeparam name="TToType">转换后的类型。</typeparam>
        /// <param name="source">要转换的对象。</param>
        /// <returns>转换类型后的对象。</returns>
        public static TToType As<TToType>(this object source)
        {
            if (source.IsNotNull())
            {
                return (TToType)source;
            }

            return default(TToType);
        }

        /// <summary>
        /// 对当前对象进行 if 判断。
        /// </summary>
        /// <typeparam name="T">对象类型。</typeparam>
        /// <param name="t">对象。</param>
        /// <param name="predicate">条件判断。</param>
        /// <param name="action">满足条件后执行的方法。</param>
        /// <returns>当前对象。</returns>
        public static T If<T>(this T t, Predicate<T> predicate, Action<T> action) where T : class
        {
            if (t == null) throw new ArgumentNullException();
            if (predicate(t)) action(t);
            return t;
        }

        /// <summary>
        /// 对当前对象进行 if 判断。
        /// </summary>
        /// <typeparam name="T">对象类型。</typeparam>
        /// <param name="source">实体。</param>
        /// <param name="predicate">条件判断。</param>
        /// <param name="ifAction">满足条件时执行的方法。</param>
        /// <param name="elseAction">不满足条件时执行的方法。</param>
        /// <returns>当前对象。</returns>
        public static T If<T>(this T source, Predicate<T> predicate, Action<T> ifAction, Action elseAction) where T : class
        {
            if (source == null)
            {
                throw new ArgumentNullException();
            }
            if (predicate(source)) 
            {
                ifAction(source);
            }
            else
            {
                elseAction();
            }
            return source;
        }

        /// <summary>
        /// 对当前对象进行 if 判断。
        /// </summary>
        /// <typeparam name="T">对象类型。</typeparam>
        /// <param name="t">对象。</param>
        /// <param name="predicate">条件判断。</param>
        /// <param name="actions">满足条件后执行的方法列表。</param>
        /// <returns>当前对象。</returns>
        public static T If<T>(this T t, Predicate<T> predicate, params Action<T>[] actions) where T : class
        {
            if (t == null) throw new ArgumentNullException();
            if (predicate(t))
            {
                foreach (var action in actions)
                    action(t);
            }
            return t;
        }

        /// <summary>
        /// 对当前对象进行 if 判断。
        /// </summary>
        /// <typeparam name="T">对象类型。</typeparam>
        /// <param name="t">对象。</param>
        /// <param name="predicate">条件判断。</param>
        /// <param name="func">满足条件后执行的方法。</param>
        /// <returns>执行的方法的返回值。</returns>
        public static T If<T>(this T t, Predicate<T> predicate, Func<T, T> func) where T : struct
        {
            return predicate(t) ? func(t) : t;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static MethodInfo GetOnlyDeclaredMethod(this Type type, string name)
        {
            return type.GetDeclaredMethods(name).SingleOrDefault();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IEnumerable<MethodInfo> GetDeclaredMethods(this Type type, string name)
        {
#if NET40
            const BindingFlags bindingFlags
                = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
            return type.GetMember(name, MemberTypes.Method, bindingFlags).OfType<MethodInfo>();
#else
            return type.GetTypeInfo().GetDeclaredMethods(name);
#endif
        }
    }
}